package com.lesserpand.lspand.story.item.service.impl;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.lesserpand.lspand.story.item.entity.NewInfoQuery;
import com.lesserpand.lspand.story.item.entity.StudentQuery;
import com.lesserpand.lspand.story.item.service.StudentService;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.cluster.Health;
import io.searchbox.cluster.NodesInfo;
import io.searchbox.cluster.NodesStats;
import io.searchbox.core.Bulk;
import io.searchbox.core.Delete;
import io.searchbox.core.DeleteByQuery;
import io.searchbox.core.Get;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import io.searchbox.core.Suggest;
import io.searchbox.core.SuggestResult;
import io.searchbox.core.Update;
import io.searchbox.indices.ClearCache;
import io.searchbox.indices.CloseIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.Flush;
import io.searchbox.indices.IndicesExists;
import io.searchbox.indices.Optimize;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import static jdk.nashorn.internal.objects.Global.print;

/**
 * @author bailuo
 * @version 0.0.1
 * @package com.lesserpand.lspand.story.item.service.impl
 * @description es与关系型数据库对吧，便于理解，不准确
 * <p>
 * Relational DB -> Databases -> Tables -> Rows -> Columns
 * Elasticsearch -> Indices -> Types -> Documents -> Fields
 * @date Created in 2018/6/8 11:37
 * @company 满屋严选
 * @copyright Copyright (c) 2017
 * @modified By
 */
@Service("itemService")
public class StudentServiceImpl implements StudentService {

    static protected final Logger logger = LoggerFactory.getLogger(StudentServiceImpl.class);

    @Resource
    JestClient jestClient;

    @Override
    public void search() {
        Search search = new Search.Builder("query").addIndex("index").build();
    }

    /**
     * 清除缓存
     */
    @Override
    public JestResult clearCache() {
        ClearCache closeIndex = new ClearCache.Builder().build();
        JestResult result = null;
        try {
            result = jestClient.execute(closeIndex);
            logger.info("clearCache == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 关闭索引
     *
     * @param type ：文档表示的对象类别
     * @return
     */
    @Override
    public JestResult closeIndex(String type) {
        CloseIndex closeIndex = new CloseIndex.Builder(type).build();
        JestResult result = null;
        try {
            result = jestClient.execute(closeIndex);
            logger.info("closeIndex == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    //优化索引
    @Override
    public JestResult optimizeIndex() {
        Optimize optimize = new Optimize.Builder().build();
        JestResult result = null;
        try {
            result = jestClient.execute(optimize);
            logger.info("optimizeIndex == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    //刷新索引
    @Override
    public JestResult flushIndex() {
        Flush flush = new Flush.Builder().build();
        JestResult result = null;
        try {
            result = jestClient.execute(flush);
            logger.info("flushIndex == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    //判断索引是否存在
    @Override
    public JestResult indicesExists() {
        IndicesExists indicesExists = new IndicesExists.Builder("article").build();
        JestResult result = null;
        try {
            result = jestClient.execute(indicesExists);
            logger.info("indicesExists == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    //查看节点信息
    @Override
    public JestResult nodesInfo() {
        NodesInfo nodesInfo = new NodesInfo.Builder().build();
        JestResult result = null;
        try {
            result = jestClient.execute(nodesInfo);
            logger.info("nodesInfo == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    //查看集群健康信息
    @Override
    public JestResult health() {
        Health health = new Health.Builder().build();
        JestResult result = null;
        try {
            result = jestClient.execute(health);
            logger.info("health == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    //节点状态
    @Override
    public JestResult nodesStats() {
        NodesStats nodesStats = new NodesStats.Builder().build();
        JestResult result = null;
        try {
            result = jestClient.execute(nodesStats);
            logger.info("nodesStats == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 更新Document
     *
     * @param index ：文档在哪存放
     * @param type  ： 文档表示的对象类别
     * @param id    ：文档唯一标识
     */
    @Override
    public JestResult updateDocument(String script, String index, String type, String id) {
        /*String script = "{" +
                "    \"doc\" : {" +
                "        \"title\" : \""+article.getTitle()+"\"," +
                "        \"content\" : \""+article.getContent()+"\"," +
                "        \"author\" : \""+article.getAuthor()+"\"," +
                "        \"source\" : \""+article.getSource()+"\"," +
                "        \"url\" : \""+article.getUrl()+"\"," +
                "        \"pubdate\" : \""+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").format(article.getPubdate())+"\"" +
                "    }" +
                "}";*/
        Update update = new Update.Builder(script).index(index).type(type).id(id).build();
        JestResult result = null;
        try {
            result = jestClient.execute(update);
            logger.info("updateDocument == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 删除index索引
     *
     * @param index
     */
    @Override
    public JestResult deleteIndex(String index) {
        DeleteIndex deleteIndex = new DeleteIndex.Builder(index).build();
        JestResult result = null;
        try {
            result = jestClient.execute(deleteIndex);
            logger.info(String.format("deleteIndex ==", result.getJsonString()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 删除type
     *
     * @param type ：当前删除document名称
     * @return
     */
    @Override
    public JestResult deleteType(String index, String type) {
        DeleteIndex deleteIndex = new DeleteIndex.Builder(index).type(type).build();
        JestResult result = null;
        try {
            result = jestClient.execute(deleteIndex);
            logger.info(String.format("deleteIndex ==", result.getJsonString()));
        } catch (IOException e) {
            logger.error("", e);
        }
        return result;
    }

    /**
     * 删除Document
     *
     * @param index ：文档在哪存放
     * @param type  ： 文档表示的对象类别
     * @param id    ：文档唯一标识
     * @return
     */
    @Override
    public JestResult deleteDocumentById(String index, String type, String id) {
        Delete delete = new Delete.Builder(id).index(index).type(type).build();
        JestResult result = null;
        try {
            result = jestClient.execute(delete);
            logger.info("deleteDocument == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 批量删除
     *
     * @param index
     * @param type
     * @param params
     */
    @Override
    public JestResult deleteDocumentByQuery(String index, String type, String params) {
        DeleteByQuery db = new DeleteByQuery.Builder(params).addIndex(index).addType(type).build();
        JestResult result = null;
        try {
            result = jestClient.execute(db);
            logger.info("deleteDocument == " + result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取Document
     *
     * @param index ：文档在哪存放
     * @param type  ： 文档表示的对象类别
     * @param id    ：文档唯一标识
     * @return
     */
    @Override
    public <T> JestResult getDocument(T object, String index, String type, String id) {
        Get get = new Get.Builder(index, id).type(type).build();
        JestResult result = null;
        try {
            result = jestClient.execute(get);
            T o = (T) result.getSourceAsObject(object.getClass());
            for (Method method : o.getClass().getMethods()) {
                logger.info("getDocument == " + method.getName());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;

    }

    @Override
    public List<SuggestResult.Suggestion> suggest() {
        String suggestionName = "my-suggestion";
        Suggest suggest = new Suggest.Builder("{" +
                "  \"" + suggestionName + "\" : {" +
                "    \"text\" : \"the amsterdma meetpu\"," +
                "    \"term\" : {" +
                "      \"field\" : \"body\"" +
                "    }" +
                "  }" +
                "}").build();
        SuggestResult suggestResult = null;
        List<SuggestResult.Suggestion> suggestionList = null;
        try {
            suggestResult = jestClient.execute(suggest);
            logger.info("suggestResult.isSucceeded() == " + suggestResult.isSucceeded());
            suggestionList = suggestResult.getSuggestions(suggestionName);
            logger.info("suggestionList.size() == " + suggestionList.size());
            for (SuggestResult.Suggestion suggestion : suggestionList) {
                System.out.println(suggestion.text);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return suggestionList;
    }

    /**
     * 查询全部
     *
     * @param index ：文档在哪存放
     * @return
     */
    @Override
    public <T> List<SearchResult.Hit<T, Void>> searchAll(String index, T o) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex(index).build();
        SearchResult result;
        List<?> hits = null;
        try {
            result = jestClient.execute(search);
            logger.info("本次查询共查到: ", result.getTotal());
            if (null == result.getTotal()) {
                return Collections.emptyList();
            }
            hits = result.getHits(o.getClass());
        } catch (IOException e) {
            logger.error("", e);
        }
        return (List<SearchResult.Hit<T, Void>>) hits;
    }

    /**
     * 分页查询
     *
     * @param o
     * @param query
     * @param index
     * @param type
     * @param <T>
     * @return
     */
    @Override
    public <T> JestResult pagination(T o, StudentQuery query, String index, String type) {
        int pageNum = null == query.getPageNum() ? 1 : query.getPageNum();
        int pageSize = null == query.getPageSize() ? 10 : query.getPageSize();

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.from((pageNum - 1) * pageSize);
        searchSourceBuilder.size(pageSize);

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        String name = query.getName();
        if (null != name) {
            boolQueryBuilder.must(QueryBuilders.termQuery("name", name));
        }

        String keyWord = query.getKeyWord();
        if (null != keyWord) {
            boolQueryBuilder.must(QueryBuilders.termQuery("details", keyWord));
        }

        Timestamp startTime = query.getStartTime();
        Timestamp endTime = query.getEndTime();
        if (null != startTime && null != endTime) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("gmtCreate").from(startTime).to(endTime));
        }

        searchSourceBuilder.query(boolQueryBuilder);
        Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex(index).addType(type).build();
        SearchResult result = null;
        Long total = 0L;
        try {
            result = jestClient.execute(search);
            total = result.getTotal();
            if (!Objects.equals(total, 0L)) {
                List<SearchResult.Hit<Object, Void>> hits = result.getHits(Object.class);
            }
        } catch (Exception e) {

        }
        return result;
    }

    /**
     * 搜索
     *
     * @param keyWord ：搜索关键字
     * @return
     */
    @Override
    public <T> List<SearchResult.Hit<T, Void>> createSearch(String keyWord, String index, T o, String... fields) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.queryStringQuery(keyWord));
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        for (String field : fields) {
            //高亮field
            highlightBuilder.field(field);
        }
        //高亮标签
        highlightBuilder.preTags("<em>").postTags("</em>");
        //高亮内容长度
        highlightBuilder.fragmentSize(200);
        Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex(index).build();
        SearchResult result;
        List<?> hits = null;
        try {
            result = jestClient.execute(search);
            logger.info("本次查询共查到：%d, 个结果！", result.getTotal());
            if (null == result.getTotal()) {
                return Collections.emptyList();
            }
            hits = result.getHits(o.getClass());
        } catch (IOException e) {
            logger.error("", e);
        }
        return (List<SearchResult.Hit<T, Void>>) hits;
    }

    //bulkIndex操作
    @Override
    public <T> void bulkIndex(String index, String type, T o) {
        Bulk bulk = new Bulk.Builder()
                .defaultIndex(index)
                .defaultType(type)
                .addAction(Arrays.asList(
                        new Index.Builder(o).build()
                )).build();
        try {
            jestClient.execute(bulk);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建索引
     *
     * @param o     ：返回对象
     * @param index ：文档在哪存放
     * @param type  ： 文档表示的对象类别
     * @return
     */
    @Override
    public <T> JestResult createIndex(T o, String index, String type) {
        Class clazz = o.getClass();
        String id = null;
        try {
            Field idName = clazz.getDeclaredField("id");
            idName.setAccessible(true);
            id = String.valueOf(idName.get(o));
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        Index index1 = new Index.Builder(o).id(id).index(index).type(type).build();
        JestResult jestResult = null;
        try {
            jestResult = jestClient.execute(index1);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jestResult;
    }

    /**
     * 搜索事件流图表数据
     *
     * @param param
     * @return
     */
    @Override
    public JsonObject searchEvent(String param) {
        JsonObject returnData = new JsonParser().parse(param).getAsJsonObject();
        Search search = new Search.Builder(returnData.toString()).addType("event").addIndex("pi").build();

//      Gson gs = new Gson();
//      System.out.println("输入参数为：" + "\n" + gs.toJson(search));

        SearchResult result = null;
        try {
            result = jestClient.execute(search);

            logger.info("本次查询共查到：%d 个结果！", result.getTotal());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result.getJsonObject();
    }
}
